package spoon.service;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.transaction.annotation.Transactional;

import spoon.core.domain.Game;
import spoon.core.exception.ConvertException;
import spoon.core.service.HttpService;
import spoon.dao.WilliamhillDao;

public abstract class WilliamhillAbstractService implements WilliamhillService {

	@Autowired
	protected HttpService httpService;

	@Autowired
	private WilliamhillDao williamhillDao;

	@Value("#{williamhill['site']}")
	protected String SITE;

	@Value("#{williamhill['url']}")
	protected String URL;

	@Value("#{williamhill['link']}")
	protected String LINK;

	protected String GATE_URL;

	protected String ITEM_CODE;

	protected String ITEM_NAME;

	protected Map<String, String> leagueMap;

	protected Map<String, String> teamMap;

	protected Logger log = LoggerFactory.getLogger(this.getClass());

	@Override
	public abstract Elements getLeagueList();

	@Override
	public abstract void getLeague(Element element);

	/**
	 * 리그코드 변경
	 * 
	 * @param league
	 * @return
	 */
	protected String getLeagueCode(String league) {
		String leagueCode = leagueMap.get(league);
		if (leagueCode == null || "".equals(leagueCode)) {
			leagueCode = league;
			// log.error("{} {} 리그코드 변경에러, 리그명 = {}", SITE, ITEM_NAME, league);
		}
		return leagueCode;
	}

	/**
	 * 팀코드 변경
	 * 
	 * @param team
	 * @return
	 */
	protected String getTeamCode(String team) {
		String teamCode = teamMap.get(team);
		if (teamCode == null || "".equals(teamCode)) {
			teamCode = team;
			// log.error("{} {} 팀코드 변경에러, 팀명 = {}", SITE, ITEM_NAME, team);
		}
		return teamCode;
	}

	protected String getGoalsNumber(String source) {
		Pattern p = Pattern.compile("((\\+|-)[0-9.])");
		Matcher m = p.matcher(source);
		if (!m.find()) {
			return "0";
		}
		return m.group(1);
	}
	
	protected String getHandicapNumber(String source) {
		Pattern p = Pattern.compile("([0-9].[0-9])");
		Matcher m = p.matcher(source);
		if (!m.find()) {
			return "0";
		}
		return m.group(1);
	}

	/**
	 * 날짜 변환 표준시간으로 변환
	 * 
	 * @param dt
	 * @return
	 */
	protected Date convertDate(String dt) {
		DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		TimeZone tz = TimeZone.getTimeZone("Greenwich");
		df.setTimeZone(tz);

		Date date = new Date();
		try {
			date = df.parse(dt);
		} catch (ParseException e) {
			throw new ConvertException(new Throwable(SITE + " " + ITEM_NAME + " 날짜변경 에러 (" + dt + ")", e));
		}
		return date;
	}

	/**
	 * 배당변환 분수 형태를 소수점 형태로
	 * 
	 * @param rate
	 * @return
	 */
	protected Double convertRate(String rate) {
		if (rate == null || "".equals(rate)) {
			return 0D;
		}

		Double d = 0D;
		if ("EVS".equals(rate)) {
			d = 2D;
		} else if (rate.contains("/")) {
			String[] s = rate.split("/");
			d = 1D + (Double.parseDouble(s[0]) / Double.parseDouble(s[1]));
		} else {
			d = Double.parseDouble(rate);
		}
		return Double.parseDouble(String.format("%.2f", d - 0.005));
	}

	/**
	 * 핸디캡 변환
	 * 
	 * @param handicap
	 * @return
	 */
	protected Double convertHandicap(String handicap) {
		Double d = null;

		if (handicap == null || "".equals(handicap)) {
			d = 0D;
		} else if (handicap.contains(",")) {
			String[] hs = handicap.split(",");
			d = (Double.parseDouble(hs[0]) + Double.parseDouble(hs[1])) / 2D;
		} else {
			d = Double.parseDouble(handicap);
		}

		return d;
	}
	
	/**
	 * Match 1X2
	 * 
	 * @param game
	 * @param map
	 * @param table
	 */
	protected void betMatch(Game game, Map<String, String> map, Element table) {
		Elements tds = table.select("tbody td");
		Game betting;

		for (Element td : tds) {
			String rate = td.select(".eventprice").text();
			String name = td.select(".eventselection").text();

			betting = new Game();

			betting.setBetTarget(map.get("betTarget"));
			betting.setBetTime(map.get("betTime"));
			betting.setBetType(map.get("betType"));
			betting.setBetName(map.get("betName"));
			betting.setHandicap(0D);
			betting.setHandicapName("");
			betting.setBetRate(convertRate(rate));
			betting.setBetRateName(name);

			if (name.equals(game.getHomeTeamName())) { // 1
				betting.setBetRateCode("1");
			} else if (name.equals("Draw")) { // X
				betting.setBetRateCode("X");
			} else { // 2
				betting.setBetRateCode("2");
			}
			game.addGameList(betting);
		}
	}

	/**
	 * 더블찬스
	 * 
	 * @param game
	 * @param map
	 * @param table
	 */
	protected void betDoubleChance(Game game, Map<String, String> map, Element table) {
		Elements tds = table.select("tbody td");
		Game betting;

		for (Element td : tds) {
			String rate = td.select(".eventprice").text();
			String name = td.select(".eventselection").text();

			betting = new Game();

			betting.setBetTarget(map.get("betTarget"));
			betting.setBetTime(map.get("betTime"));
			betting.setBetType(map.get("betType"));
			betting.setBetName(map.get("betName"));
			betting.setHandicap(0D);
			betting.setHandicapName("");
			betting.setBetRate(convertRate(rate));
			betting.setBetRateName(name);

			if (name.startsWith("Draw")) { // X2
				betting.setBetRateCode("X2");
			} else if (name.endsWith("Draw")) { // 1X
				betting.setBetRateCode("1X");
			} else { // 12
				betting.setBetRateCode("12");
			}
			game.addGameList(betting);
		}
	}

	/**
	 * Draw No Bet
	 * 
	 * @param game
	 * @param table
	 */
	protected void betDrawNoBet(Game game, Element table) {
		Game betting;

		// Home
		betting = new Game();
		betting.setBetTarget("Goals");
		betting.setBetTime("FT");
		betting.setBetType("DNB");
		betting.setBetName("Draw No Bet");
		betting.setHandicap(0D);
		betting.setHandicapName("");
		betting.setBetRate(convertRate(table.select(".eventprice").first().text()));
		betting.setBetRateCode("1");
		betting.setBetRateName(table.select(".eventselection").first().text());
		game.addGameList(betting);

		// Away
		betting = new Game();
		betting.setBetTarget("Goals");
		betting.setBetTime("FT");
		betting.setBetType("DNB");
		betting.setBetName("Draw No Bet");
		betting.setHandicap(0D);
		betting.setHandicapName("");
		betting.setBetRate(convertRate(table.select(".eventprice").last().text()));
		betting.setBetRateCode("2");
		betting.setBetRateName(table.select(".eventselection").last().text());
		game.addGameList(betting);
	}

	/**
	 * Match Handicaps 1X2
	 * 
	 * @param game
	 * @param table
	 */
	protected void betMatchHandicap(Game game, Element table) {
		Game betting;

		Elements trs = table.select("tbody tr");

		for (Element tr : trs) {
			String handicap = getGoalsNumber(tr.select(".eventselection").text());

			// Home
			betting = new Game();
			betting.setBetTarget("Goals");
			betting.setBetTime("FT");
			betting.setBetType("MH");
			betting.setBetName("Match Handicaps");
			betting.setHandicap(convertHandicap(handicap));
			betting.setHandicapName(tr.select(".eventselection").get(0).text());
			betting.setBetRate(convertRate(tr.select(".eventprice").get(0).text()));
			betting.setBetRateCode("1");
			betting.setBetRateName(table.select(".eventselection").get(0).text());
			game.addGameList(betting);

			// Draw
			betting = new Game();
			betting.setBetTarget("Goals");
			betting.setBetTime("FT");
			betting.setBetType("MH");
			betting.setBetName("Match Handicaps");
			betting.setHandicap(convertHandicap(handicap));
			betting.setHandicapName(tr.select(".eventselection").get(1).text());
			betting.setBetRate(convertRate(tr.select(".eventprice").get(1).text()));
			betting.setBetRateCode("X");
			betting.setBetRateName(table.select(".eventselection").get(1).text());
			game.addGameList(betting);
			
			// Away
			betting = new Game();
			betting.setBetTarget("Goals");
			betting.setBetTime("FT");
			betting.setBetType("MH");
			betting.setBetName("Match Handicaps");
			betting.setHandicap(convertHandicap(handicap));
			betting.setHandicapName(tr.select(".eventselection").get(2).text());
			betting.setBetRate(convertRate(tr.select(".eventprice").get(2).text()));
			betting.setBetRateCode("2");
			betting.setBetRateName(table.select(".eventselection").get(2).text());
			game.addGameList(betting);

		}
	}

	/**
	 * Over/Under
	 * 
	 * @param game
	 * @param map
	 * @param table
	 */
	protected void betOverUnder(Game game, Map<String, String> map, Element table) {
		Elements tds = table.select("tbody td");
		Game betting;

		for (Element td : tds) {
			String rate = td.select(".eventprice").text();
			String name = td.select(".eventselection").text();

			betting = new Game();

			betting.setBetTarget(map.get("betTarget"));
			betting.setBetTime(map.get("betTime"));
			betting.setBetType(map.get("betType"));
			betting.setBetName(map.get("betName"));
			betting.setHandicap(convertHandicap(getHandicapNumber(name)));
			betting.setHandicapName(name);
			betting.setBetRate(convertRate(rate));
			betting.setBetRateName(name);

			if (name.startsWith("Over")) { // Over
				betting.setBetRateCode("Over");
			} else { // Under
				betting.setBetRateCode("Under");
			}
			game.addGameList(betting);
		}
	}
	
	/**
	 * 디비 입력
	 * 
	 * @param league
	 * @return
	 */
	@Transactional
	protected int addBetting(Game league) {

		williamhillDao.delete(league);
		return williamhillDao.addBetting(league);

	}

}
